/**
 *  X86Assembler.java : IceBird project
 *  20:53:06 
 */
package icebird.compiler.x86.old;

import icebird.compiler.x86.old.X86Register.FPU;
import icebird.compiler.x86.old.X86Register.GPR;

import icebird.utils.ObjectBuilder;

/**
 * @author Sergey Shulepoff[Knott]
 */
public final class X86Assembler {
	
	private ObjectBuilder obj;
	
	private boolean idented = false;
	
	/**
	 * Create x86 assembler.
	 */
	public X86Assembler() {
		obj = new ObjectBuilder();
	}
	
	public void write(Object o) {
		if (idented) {
			obj.append("\t");
		}
		
		obj.append(o);
		obj.appendln();
	}
	
	/**
	 * Comment to eol.
	 * @return void
	 */
	public void comment(String c) {
		write("; " + c);
	}
	
	/**
	 * Gets string.
	 * @return String
	 */
	public String toString() {
		return obj.toString();
	}

	/**
	 * @return the idented
	 */
	public final boolean isIdented() {
		return idented;
	}

	/**
	 * @param idented the idented to set
	 */
	public final void setIdented(boolean idented) {
		this.idented = idented;
	}
	
	public void op(String op, Object... operands) {
		if (idented) {
			obj.append("\t");
		}
		
		obj.append(op);
		obj.append("\t\t");
		
		for (Object operand : operands) {
			obj.append(operand);
			obj.append(", ");
		}
		
		obj.pop();
		obj.appendln();
	}
	
	/**
	 * Define label.
	 * @return void
	 */
	public void defineLabel(String labelName) {
		write(labelName + ":");
	}
	
	public void move(X86Register dst, X86Register src) {
		op("mov", dst, src);
	}
	
	public void move(X86Register dst, X86Register src, int srcDisp) {
		op("mov", dst, "[" + src + "+" + srcDisp + "]");
	}
	
	public void fxch(FPU fpu) {
		op("fxch", fpu);
	}
	
	public void lea(GPR dst, GPR src, int srcDisp) {
		op("lea", dst, "[" + src + "+" + srcDisp + "]");
	}
	
	public void pop(GPR reg) {
		op("pop", reg);
	}
	
	public void push(GPR reg) {
		op("push", reg);
	}
	
	public void push(int c) {
		op("push", c);
	}
	
	public void push(GPR reg, int disp) {
		op("push", "[" + reg + "+" + disp + "]");
	}
	
	public void moveConst(GPR reg, int c) {
		op("mov", reg, c);
	}
	
	public void clear(GPR reg) {
		xor(reg, reg);
	}
	
	public void inc(GPR reg) {
		op("inc", reg);
	}
	
	public void dec(GPR reg) {
		op("dec", reg);
	}
	
	public void fistp(GPR reg, int disp) {
		op("fistp", "dword [" + reg + "+" + disp + "]");
	}
	
	public void fild(GPR reg, int disp) {
		op("fild", "dword [" + reg + "+" + disp + "]");
	}
	
	public void fld(GPR reg, int disp) {
		op("fld", "dword [" + reg + "+" + disp + "]");
	}
	
	public void fst(GPR reg, int disp) {
		op("fst", "dword [" + reg + "+" + disp + "]");
	}
	
	public void add(GPR dst, GPR src) {
		op("add", dst, src);
	}
	
	public void sub(GPR dst, GPR src) {
		op("sub", dst, src);
	}
	
	public void and(GPR dst, GPR src) {
		op("and", dst, src);
	}
	
	public void or(GPR dst, GPR src) {
		op("or", dst, src);
	}
	
	public void xor(GPR src, GPR dst) {
		op("xor", src, dst);
	}
	
	public void add(GPR dst, GPR src, int disp) {
		op("add", dst, "[" + src + "+" + disp + "]");
	}
	
	public void sub(GPR dst, GPR src, int disp) {
		op("sub", dst, "[" + src + "+" + disp + "]");
	}
	
	public void and(GPR dst, GPR src, int disp) {
		op("and", dst, "[" + src + "+" + disp + "]");
	}
	
	public void or(GPR dst, GPR src, int disp) {
		op("or", dst, "[" + src + "+" + disp + "]");
	}
	
	public void xor(GPR src, GPR dst, int disp) {
		op("xor", src, "[" + src + "+" + disp + "]");
	}
	
	
	public void add(GPR dst, int src) {
		op("add", dst, src);
	}
	
	public void sub(GPR dst, int src) {
		op("sub", dst, src);
	}
	
	public void and(GPR dst, int src) {
		op("and", dst, src);
	}
	
	public void or(GPR dst, int src) {
		op("or", dst, src);
	}
	
	public void xor(GPR src, int dst) {
		op("xor", src, dst);
	}
	
	public void artOp(int op, GPR dst, GPR src) { 
		switch (op) {
		
		case X86Operation.ADD:
			add(dst, src);
			break;
			
		case X86Operation.SUB:
			sub(dst, src);
			break;
			
		case X86Operation.AND:
			and(dst, src);
			break;
			
		case X86Operation.OR:
			or(dst, src);
			break;
			
		case X86Operation.XOR:
			xor(dst, src);
			break;
		
		default:
			throw new RuntimeException("Unknown operation.");
		}
	}
	
	public void artOp(int op, GPR dst, GPR src, int srcDisp) { 
		switch (op) {
		
		case X86Operation.ADD:
			add(dst, src, srcDisp);
			break;
			
		case X86Operation.SUB:
			sub(dst, src, srcDisp);
			break;
			
		case X86Operation.AND:
			and(dst, src, srcDisp);
			break;
			
		case X86Operation.OR:
			or(dst, src, srcDisp);
			break;
			
		case X86Operation.XOR:
			xor(dst, src, srcDisp);
			break;
		
		default:
			throw new RuntimeException("Unknown operation.");
		}
	}
	
	public void artOp(int op, GPR dst, int src) { 
		switch (op) {
		
		case X86Operation.ADD:
			add(dst, src);
			break;
			
		case X86Operation.SUB:
			sub(dst, src);
			break;
			
		case X86Operation.AND:
			and(dst, src);
			break;
			
		case X86Operation.OR:
			or(dst, src);
			break;
			
		case X86Operation.XOR:
			xor(dst, src);
			break;
		
		default:
			throw new RuntimeException("Unknown operation.");
		}
	}
}
